package com.budwk.app.sqfwDoc.codeGeneratorV2.generate;

import cn.hutool.core.date.DateUtil;
import com.budwk.app.sqfwDoc.bo.ExcelCreateConfig;
import com.budwk.app.sqfwDoc.codeGenerator.cusType.SqfwImage;
import com.budwk.app.sqfwDoc.codeGenerator.pdfGenerate.AbstractCustomerPdfCreateField;
import com.budwk.app.sqfwDoc.codeGeneratorV2.constants.CodeGeneratorConstants;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.CommonParam;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.ExcelGenerateParam;
import com.budwk.app.sqfwDoc.codeGeneratorV2.fileParam.ExcelRowDataParam;
import com.budwk.app.util.poiUtils.excelPictureConfigBO.ExcelFileCreateParamBO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.budwk.app.util.poiUtils.CommonFormOfficeUtils.*;

/**
 * @author ZY.Wang
 * @since 2024/1/25
 * <p>
 * 这个类是excel处理器的基础类，专门负责单个excel的生成
 * <p/>
 */
public abstract class BaseExcelGenerator {

    private ExcelGenerateParam excelGenerateParam;

    protected final Map<String, String> headerDataFormatMap = Maps.newHashMap();
    protected final Map<String, String> sheetDateFormatMap = Maps.newHashMap();

    public ResultOfExcelGenerator createExcel(ExcelGenerateParam excelGenerateParam) {

        createExcelStart(excelGenerateParam);

        this.excelGenerateParam = excelGenerateParam;

        initHeaderDataFormatMap();
        initSheetDateFormatMap();

        ResultOfExcelGenerator result = new ResultOfExcelGenerator();

        ExcelCreateConfig excelConfig = excelGenerateParam.getExcelConfig();

        Map<String, Object> excelParam = Maps.newHashMap();

        popularSheetBaseParam(excelParam, excelGenerateParam);
        customerPopularHeaderData(excelParam, excelGenerateParam);
        if (StringUtils.isNotBlank(excelGenerateParam.getClientType())) {
            if (excelGenerateParam.getClientType().equals(CodeGeneratorConstants.CLIENT_TYPE_ADMIN))
                customerPopularHeaderDataForAdmin(excelParam, excelGenerateParam);
        }

        List<Map<String, Object>> listMap = Lists.newArrayList();
        Boolean onlyGenerateTemplateFlag = excelConfig.getOnlyGenerateTemplateFlag();
        Boolean createExcelFileFlag = Optional.ofNullable(excelGenerateParam.getExcelConfig().getCreateExcelFileFlag()).orElse(true);

        // 如果不是下载空的模板需要进行填充数据
        if (!onlyGenerateTemplateFlag) {
            // 判断excel是否有数据
            ResultOfExcelDataInto dataInfoFlag = judgeExcelHaveDataBeforeErgodic(excelParam, excelGenerateParam);

            if (dataInfoFlag != null) {
                boolean haveDataFlag = Optional.ofNullable(dataInfoFlag.getExcelHaveDataFlag()).orElse(true);
                if (!createExcelFileFlag) {
                    result.setPassCreateConditionFlag(haveDataFlag);
                    result.setNotCreateMark(dataInfoFlag.getRemark());
                    return result;
                }
            }

            popularSheetDataList(listMap, excelGenerateParam);
            customerPopularSheetData(listMap, excelGenerateParam);

            excelParam.put("list", listMap);
            dataInfoFlag = judgeExcelHaveDataBeforeCreate(excelParam, excelGenerateParam);
            if (dataInfoFlag != null) {
                boolean haveDataFlag = Optional.ofNullable(dataInfoFlag.getExcelHaveDataFlag()).orElse(true);
                if (!createExcelFileFlag) {
                    result.setPassCreateConditionFlag(haveDataFlag);
                    result.setNotCreateMark(dataInfoFlag.getRemark());
                    return result;
                }
            }
        }

        String templateName = getTemplatePath(excelGenerateParam);
        String templatePath = getTemplatePathByOS(templateName);

        String fileName = getDownloadFileName(excelGenerateParam);

        ExcelFileCreateParamBO excelFileCreateParam = new ExcelFileCreateParamBO();
        excelFileCreateParam.setTemplatePath(templatePath);
        excelFileCreateParam.setSheetParam(excelParam);
        excelFileCreateParam.setDataList(listMap);
        excelFileCreateParam.setFileName(fileName);
        excelFileCreateParam.setClazz(getImageConfigBO());
        excelFileCreateParam.setListNotLastRow(!excelConfig.getListAtLastRowFlag());
        excelFileCreateParam.setRowHeight(excelConfig.getRowHeight());
        excelFileCreateParam.setImgWidth(excelConfig.getImgWidth());
        excelFileCreateParam.setReturnWebUrlFlag(excelConfig.getReturnWebUrlFlag());
        completeExcelFileCreateParam(excelFileCreateParam);

        result.setPassCreateConditionFlag(true);
        result.setExcelUrl(createExcelAndUpload(excelFileCreateParam));

        createExcelEnd(excelGenerateParam, excelFileCreateParam, result);

        return result;
    }

    protected void createExcelEnd(ExcelGenerateParam excelGenerateParam, ExcelFileCreateParamBO excelFileCreateParam, ResultOfExcelGenerator result) {

    }

    protected void createExcelStart(ExcelGenerateParam excelGenerateParam) {

    }

    protected void initHeaderDataFormatMap() {
        headerDataFormatMap.put("downloadDateStr", "yyyy-MM-dd");
    }

    protected void initSheetDateFormatMap() {

    }

    protected void popularSheetBaseParam(Map<String, Object> excelParam, ExcelGenerateParam excelGenerateParam) {
        CommonParam downloadUserParam = excelGenerateParam.getDownloadUserParam();
        excelParam.put("unitName", downloadUserParam.getUnitName());
        excelParam.put("downloadDateStr", DateUtil.format(new Date(), "yyyy-MM-dd"));
        excelParam.put("createUserName", downloadUserParam.getCreateUserName());
        excelParam.put("createUserPhone", downloadUserParam.getCreateUserPhone());
        excelParam.put("province", downloadUserParam.getProvince());
        excelParam.put("city", downloadUserParam.getCity());
        excelParam.put("district", downloadUserParam.getDistrict());
        excelParam.put("county", downloadUserParam.getCounty());
        excelParam.put("community", downloadUserParam.getCommunity());
        excelParam.put("levelCityUnitName", downloadUserParam.getLevelCityUnitName());
    }

    protected void popularSheetDataList(List<Map<String, Object>> sheetDataMapList, ExcelGenerateParam excelGenerateParam) {

        List<ExcelRowDataParam> dataList = excelGenerateParam.getDataList();

        int rowNum = 0;
        for (ExcelRowDataParam excelRowDataParam : dataList) {
            if (!addRowDataCondition(excelRowDataParam, excelGenerateParam)) continue;

            CommonParam commonParam = excelRowDataParam.getCreateUserCommonParam();
            AbstractCustomerPdfCreateField customerPdfCreateField = excelRowDataParam.getAbstractCustomerPdfCreateField();

            Map<String, Object> rowDataMap = Maps.newHashMap();
            rowDataMap.put("num", ++rowNum);
            rowDataMap.put("createUserName", commonParam.getCreateUserName());
            Class<? extends AbstractCustomerPdfCreateField> fieldDataClass = customerPdfCreateField.getClass();
            Field[] declaredFields = fieldDataClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);

                String fieldName = declaredField.getName();

                Object fieldValue = getFieldValueByType(declaredField, customerPdfCreateField);

                rowDataMap.put(fieldName, fieldValue);
            }
            customerPopularRowDataMap(rowDataMap, excelRowDataParam);
            customerPopularRowDataMap(rowDataMap, excelRowDataParam, excelGenerateParam);
            if (StringUtils.isNotBlank(excelGenerateParam.getClientType())) {
                if (excelGenerateParam.getClientType().equals(CodeGeneratorConstants.CLIENT_TYPE_ADMIN))
                    customerPopularRowDataMapForAdmin(rowDataMap, excelRowDataParam);
            }
            sheetDataMapList.add(rowDataMap);
        }
    }

    /**
     * 从自定义字段对象反射获取属性的值
     *
     * @param declaredField 字段信息
     * @param fieldData     自定义字段对象
     * @return 结果
     */
    protected Object getFieldValueByType(Field declaredField, AbstractCustomerPdfCreateField fieldData) {

        Object fieldValue = null;

        try {
            fieldValue = declaredField.get(fieldData);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (fieldData == null) {
            return "";
        }

        // 分不同的类型进行处理，如果是字符串的话，可以直接插入数据
        if (String.class.isAssignableFrom(declaredField.getType())) {
            return fieldValue;
        }

        // 如果是时间类型，则使用默认的时间格式进行转化
        if (Date.class.isAssignableFrom(declaredField.getType())) {
            Date fileDate = (Date) fieldValue;

            return DateUtil.format(fileDate, "yyyy-MM-dd");
        }

        // 如果是照片类型则转化为图片
        if (SqfwImage.class.isAssignableFrom(declaredField.getType())) {
            Integer fillImgCount = excelGenerateParam.getExcelConfig().getFillImgCount();
            if (fillImgCount == null) fillImgCount = 2;

            SqfwImage imageData = (SqfwImage) fieldValue;

            List<byte[]> imageByteList = Lists.newArrayList();
            if (imageData == null) return imageByteList;

            List<String> pictureUrlList = imageData.getImageUrlList();
            if (pictureUrlList == null || pictureUrlList.size() == 0) return imageByteList;

            if (pictureUrlList.size() > fillImgCount) pictureUrlList = pictureUrlList.subList(0, fillImgCount);
            imageByteList = addPictureToByteList(pictureUrlList);

            return imageByteList;
        }

        return fieldValue;
    }

    /**
     * 用户自定义填充行数据
     *
     * @param rowDataMap         行数据
     * @param rowDataParam       行参数
     * @param excelGenerateParam excel参数
     */
    protected void customerPopularRowDataMap(Map<String, Object> rowDataMap, ExcelRowDataParam rowDataParam, ExcelGenerateParam excelGenerateParam) {

    }

    //----------------------------------------------------------------------
    //  一些需要实现的抽象方法
    //----------------------------------------------------------------------

    protected abstract void customerPopularHeaderData(Map<String, Object> excelParam, ExcelGenerateParam excelGenerateParam);

    protected abstract void customerPopularHeaderDataForAdmin(Map<String, Object> excelParam, ExcelGenerateParam excelGenerateParam);

    protected abstract ResultOfExcelDataInto judgeExcelHaveDataBeforeErgodic(Map<String, Object> excelParam, ExcelGenerateParam excelGenerateParam);

    protected abstract boolean addRowDataCondition(ExcelRowDataParam rowDataParam, ExcelGenerateParam excelGenerateParam);

    protected abstract void customerPopularSheetData(List<Map<String, Object>> listMap, ExcelGenerateParam excelGenerateParam);

    protected abstract void customerPopularRowDataMap(Map<String, Object> rowDataMap, ExcelRowDataParam rowDataParam);

    protected abstract void customerPopularRowDataMapForAdmin(Map<String, Object> rowDataMap, ExcelRowDataParam rowDataParam);

    protected abstract ResultOfExcelDataInto judgeExcelHaveDataBeforeCreate(Map<String, Object> excelParam, ExcelGenerateParam excelGenerateParam);

    protected abstract String getTemplatePath(ExcelGenerateParam excelGenerateParam);

    protected abstract String getDownloadFileName(ExcelGenerateParam excelGenerateParam);

    protected abstract Class<?> getImageConfigBO();

    protected abstract void completeExcelFileCreateParam(ExcelFileCreateParamBO excelFileCreateParamBO);

}
